/* ************ FIGURAS.C *************************
 * 
 *   Proyecto 2: Ray Tracing Basico
 * 
 *   Prof.: 
 * 	 Francisco J. Torres Rojas PhD
 * 
 *   Autor:
 *   Andres Aguilar Umana
 *   200928927
 * 
 *   1 de Abril 2012
 * 
 ****************************************************/
 #include <figuras.h>
#include <common.h>
#include <parser.h>
 

int Calado(int text, int i, int j,Escena *escena){
	Color col = escena->Texturas[text].ima[MAX(0,j-1)][MAX(0,i-1)];
	return (col.r > 0.5 && col.g > 0.5 && col.b > 0.5);
}

long double Normalizar(Vector *vec){
	long double norma;
	 norma = NORMA((*vec)); //(*vec) es como si no fuera ptr
	 vec->dire.x = vec->dire.x / norma;
	 vec->dire.y = vec->dire.y / norma;
	 vec->dire.z = vec->dire.z / norma;
	 return norma;
}
Vector NormalEsfera(void *esfera,Punto inter){
	Esfera *esf;
	Vector res;
	esf = (Esfera *)((Objeto *)esfera)->obj;
	res.dire.x = (inter.x - esf->centro.x)/esf->radio;
	res.dire.y = (inter.y - esf->centro.y)/esf->radio;
	res.dire.z = (inter.z - esf->centro.z)/esf->radio;
	return res;
}
Vector NormalCilindro(void *cilindro,Punto inter){
	Cilindro *cil;
	Vector res;
	cil = (Cilindro *)((Objeto *)cilindro)->obj;
	long double d = ((Objeto *)cilindro)->d;
	                
	res.dire.x = (inter.x - (cil->rayo.ancla.x + d * cil->rayo.vector.dire.x))/cil->radio;
	res.dire.y = (inter.y - (cil->rayo.ancla.y + d * cil->rayo.vector.dire.y))/cil->radio;
	res.dire.z = (inter.z - (cil->rayo.ancla.z + d * cil->rayo.vector.dire.z))/cil->radio;
	return res;
}
Vector NormalCono(void *cono, Punto inter){
	Cono *con;
	Vector res;
	con = (Cono *)((Objeto *)cono)->obj;
	long double d = ((Objeto *)cono)->d;
	long double tx,ty,tz,XQ,YQ,ZQ;
	
	XQ = con->rayo.vector.dire.x;
	YQ = con->rayo.vector.dire.y;
	ZQ = con->rayo.vector.dire.z;
	
	tx = con->rayo.ancla.x + d * XQ - inter.x;
	ty = con->rayo.ancla.y + d * YQ - inter.y;
	tz = con->rayo.ancla.z + d * ZQ - inter.z;
	                
	res.dire.x = 2 * (tx * (XQ * XQ - 1) + ty * XQ * YQ + tz * XQ*ZQ - con->uv*d*XQ);
	
	res.dire.y = 2*(tx*XQ*YQ + ty*(YQ*YQ-1) + tz*YQ*ZQ - con->uv*d*YQ);
	res.dire.z = 2*(tx*XQ*ZQ + ty*YQ*ZQ + tz*(ZQ*ZQ-1) - con->uv*d*ZQ);
	Normalizar(&res);
	return res;
}

Vector NormalPoligono(void *poligono,Punto inter){
	return ((Poligono *)((Objeto *)poligono)->obj)->Normal;
}
Vector NormalCuadratica(void *cuadratica,Punto inter){
	Vector vec;
	Cuadratica *cua = ((Cuadratica *)((Objeto *)cuadratica)->obj);
	vec.dire.x =  (cua->A * inter.x 
						+ cua->D * inter.y
						+ cua->F * inter.z
						+ cua->G);
	vec.dire.y =  (cua->B * inter.y
						+ cua->D * inter.x
						+ cua->E * inter.z 
						+ cua->H);
	vec.dire.z =  (cua->C * inter.z
						+ cua->E * inter.y
						+ cua->F * inter.x
						+ cua->J);
	Normalizar(&vec);
	
	return vec;
}

Interseccion InterEsfera(Rayo ray,long double *t,Esfera cirTemp,Escena *escena){
	long double a,b,c;
	long double Xe_Xc,Ye_Yc,Ze_Zc;
	long double discr;
	long double temp1,temp2;
	long double sqr;
	long double t2;
	long double res;
	int i;
	char nohay;
	Interseccion inter;

	Xe_Xc = ray.ancla.x - cirTemp.centro.x;
	Ye_Yc = ray.ancla.y - cirTemp.centro.y;
	Ze_Zc = ray.ancla.z - cirTemp.centro.z;
	a = 1.0;
	b = 2.0 * (Xe_Xc * ray.vector.dire.x + Ye_Yc * ray.vector.dire.y
			+ Ze_Zc * ray.vector.dire.z);
	c = ((Xe_Xc * Xe_Xc)+ (Ye_Yc * Ye_Yc)+ (Ze_Zc * Ze_Zc)
			- (cirTemp.radio2));
	discr = (b * b) - (4 * c * a); //Se omite el a xq a = 1.0 (Esfera)
	if (discr < 0){
		*t = INFINITY;
		inter.t = *t;
		return inter;
	}
	sqr = sqrtl(discr);
	temp1 = (-b + sqr)/2.0;
	temp2 = (-b - sqr)/2.0;
	inter.objeto.color = cirTemp.color;
	if (temp1 < 0.0)
		temp1 = INFINITY;
	if (temp2 < 0.0)
		temp2 = INFINITY;

	*t = MIN(temp1,temp2);
	if (*t<=EPSILON){
		*t = MAX(temp1,temp2);
		t2 = MIN(temp1,temp2);
	}else{
		t2 = MAX(temp1,temp2);
	}
	inter.t = *t;

	inter.Pint.x = ray.ancla.x + (*t) * ray.vector.dire.x;
	inter.Pint.y = ray.ancla.y + (*t) * ray.vector.dire.y;
	inter.Pint.z = ray.ancla.z + (*t) * ray.vector.dire.z;
	nohay = 0;
	if (cirTemp.cortes>0){
		for (i=0;i<cirTemp.cortes;i++){
			res = escena->Planos[cirTemp.planos_corte[i]].ABC.dire.x * inter.Pint.x;
			res += escena->Planos[cirTemp.planos_corte[i]].ABC.dire.y * inter.Pint.y;
			res += escena->Planos[cirTemp.planos_corte[i]].ABC.dire.z * inter.Pint.z;
			res += escena->Planos[cirTemp.planos_corte[i]].D;
			if ((escena->Planos[cirTemp.planos_corte[i]].dire && res<0)
					|| (!escena->Planos[cirTemp.planos_corte[i]].dire && res>0)){
				nohay = 1;
			}
		}
		if (nohay){
			inter.t = *t;
			*t = t2;
			t2 = inter.t;
			inter.Pint.x = ray.ancla.x + (*t) * ray.vector.dire.x;
			inter.Pint.y = ray.ancla.y + (*t) * ray.vector.dire.y;
			inter.Pint.z = ray.ancla.z + (*t) * ray.vector.dire.z;
			inter.t = *t;
			for (i=0;i<cirTemp.cortes;i++){
				res = escena->Planos[cirTemp.planos_corte[i]].ABC.dire.x * inter.Pint.x;
				res += escena->Planos[cirTemp.planos_corte[i]].ABC.dire.y * inter.Pint.y;
				res += escena->Planos[cirTemp.planos_corte[i]].ABC.dire.z * inter.Pint.z;
				res += escena->Planos[cirTemp.planos_corte[i]].D;
				if ((escena->Planos[cirTemp.planos_corte[i]].dire && res<0)
						|| (!escena->Planos[cirTemp.planos_corte[i]].dire && res>0)){
					*t = INFINITY;
					inter.t = *t;
					return inter;
				}
			}
		}
	}
	if (*t == INFINITY){
		inter.t = *t;
		return inter;
	}
	//Mapas de Calado
	if (cirTemp.calado != -1){
		int ii,jj,pega;
		Vector N;
		Objeto Q;
		Q.obj = &cirTemp;
		N = NormalEsfera(&Q,inter.Pint);


		//printf("esfera\n");
		posicionTexturaEsfera(cirTemp,cirTemp.calado,inter.Pint,escena,&ii,&jj,N);

		pega = Calado(cirTemp.calado,ii,jj,escena);

		if (!pega && t2!=INFINITY && t2>EPSILON){
			*t = t2;
			inter.Pint.x = ray.ancla.x + *t * ray.vector.dire.x;
			inter.Pint.y = ray.ancla.y + *t * ray.vector.dire.y;
			inter.Pint.z = ray.ancla.z + *t * ray.vector.dire.z;
			N = NormalEsfera(&Q,inter.Pint);
			posicionTexturaEsfera(cirTemp,cirTemp.calado,inter.Pint,escena,&ii,&jj,N);

			pega = Calado(cirTemp.calado,ii,jj,escena);
			if (!pega){
				*t = INFINITY;
				inter.t = *t;
				return inter;
			}
		}
	}
	return inter;
}

Interseccion InterCilindro(Rayo ray,long double *t,Cilindro cilTemp,Escena *escena){
	long double a,b,c;
	long double discr;
	long double temp1,temp2;
	long double sqr;

	long double Xd,Yd,Zd;
	long double Xq,Yq,Zq;
	long double X0,Y0,Z0;
	long double Xe,Ye,Ze;
	long double A,B,C,D,E,F,G,H,I;
	long double t2;
	long double res;
	char nohay;
	int i;
	Punto Q = cilTemp.rayo.vector.dire;
	Interseccion inter;

	Xe = ray.ancla.x;
	Ye = ray.ancla.y;
	Ze = ray.ancla.z;

	Xq = Q.x;
	Yq = Q.y;
	Zq = Q.z;

	Xd = ray.vector.dire.x;
	Yd = ray.vector.dire.y;
	Zd = ray.vector.dire.z;

	X0 = cilTemp.rayo.ancla.x;
	Y0 = cilTemp.rayo.ancla.y;
	Z0 = cilTemp.rayo.ancla.z;

	A = cilTemp.A;
	B = cilTemp.B;
	C = cilTemp.C;

	D = ((Xq * Xq * Xd) + (A * Yd) + (B * Zd) - Xd);
	E = ((Yq * Yq * Yd) + (A * Xd) + (C * Zd) - Yd);
	F = ((Zq * Zq * Zd) + (B * Xd) + (C * Yd) - Zd);
	G = (Xe - X0);
	H = (Ye - Y0);
	I = (Ze - Z0);

	a = ((D * D) + (E * E) + (F * F));

	b = 2 * ((X0 * D) + (Y0 * E) + (Z0 * F) - (Xe * D) - (Ye * E) - (Ze * F)
			+ (G * ((Xq * Xq * D) + (E * A) + (F * B)))
			+ (H * ((D * A) + (Yq * Yq * E) + (F * C)))
			+ (I * ((D * B) + (E * C) + (Zq * Zq * F))));

	c = (X0 * X0) + (Y0 * Y0) + (Z0 * Z0) + (Xe * Xe) + (Ye * Ye) + (Ze * Ze);
	c += (G * G * (pow(Xq,4) + (A * A) + (B * B)));
	c += (H * H * (pow(Yq,4) + (A * A) + (C * C)));
	c += (I * I * (pow(Zq,4) + (B * B) + (C * C)));
	c += 2 * (G * ((Xq * Xq)*(X0 - Xe) + A * (Y0 - Ye) + B * (Z0 - Ze)));
	c += 2 * (H * (A * (X0 - Xe) + (Yq * Yq) * (Y0 - Ye) + C * (Z0 - Ze)));
	c += 2 * (I * (B * (X0 - Xe) + C * (Y0 - Ye) + (Zq * Zq) * (Z0 - Ze)));
	c += (2 * G * H * (A * ((Xq * Xq) + (Yq * Yq)) + (B * C)));
	c += (2 * G * I * (B * ((Xq * Xq) + (Zq * Zq)) + (A * C)));
	c += (2 * H * I * ((A * B) + C * ((Yq * Yq) + (Zq * Zq))));
	c += -2 * ((X0 * Xe) + (Y0 * Ye) + (Z0 * Ze));
	c -= cilTemp.radio2;


	discr = (b * b) - (4 * c * a);
	if (discr < EPSILON){
		*t = INFINITY;
		inter.t = *t;
		return inter;
	}
	sqr = sqrtl(discr);
	temp1 = (-b + sqr)/(2.0 * a);
	temp2 = (-b - sqr)/(2.0 * a);
	inter.objeto.color = cilTemp.color;
	if (temp1 < EPSILON)
		temp1 = INFINITY;
	if (temp2 < EPSILON)
		temp2 = INFINITY;
	*t = MIN(temp1,temp2);
	if (*t<=EPSILON){
		*t = MAX(temp1,temp2);
		t2 = MIN(temp1,temp2);
	}else{
		t2 = MAX(temp1,temp2);
	}
	if (*t<=EPSILON){
		*t = INFINITY;
		inter.t = *t;
		return inter;
	}

	inter.Pint.x = ray.ancla.x + *t * ray.vector.dire.x;
	inter.Pint.y = ray.ancla.y + *t * ray.vector.dire.y;
	inter.Pint.z = ray.ancla.z + *t * ray.vector.dire.z;

	nohay = 0;
	if (cilTemp.cortes>0){
		for (i=0;i<cilTemp.cortes;i++){
			res = escena->Planos[cilTemp.planos_corte[i]].ABC.dire.x * inter.Pint.x;
			res += escena->Planos[cilTemp.planos_corte[i]].ABC.dire.y * inter.Pint.y;
			res += escena->Planos[cilTemp.planos_corte[i]].ABC.dire.z * inter.Pint.z;
			res += escena->Planos[cilTemp.planos_corte[i]].D;
			if ((escena->Planos[cilTemp.planos_corte[i]].dire && res<0)
					|| (!escena->Planos[cilTemp.planos_corte[i]].dire && res>0)){
				nohay = 1;
			}
		}
		if (nohay){
			inter.t = *t;
			*t = t2;
			t2 = inter.t;
			inter.Pint.x = ray.ancla.x + (*t) * ray.vector.dire.x;
			inter.Pint.y = ray.ancla.y + (*t) * ray.vector.dire.y;
			inter.Pint.z = ray.ancla.z + (*t) * ray.vector.dire.z;
			inter.t = *t;
			for (i=0;i<cilTemp.cortes;i++){
				res = escena->Planos[cilTemp.planos_corte[i]].ABC.dire.x * inter.Pint.x;
				res += escena->Planos[cilTemp.planos_corte[i]].ABC.dire.y * inter.Pint.y;
				res += escena->Planos[cilTemp.planos_corte[i]].ABC.dire.z * inter.Pint.z;
				res += escena->Planos[cilTemp.planos_corte[i]].D;
				if ((escena->Planos[cilTemp.planos_corte[i]].dire && res<0)
						|| (!escena->Planos[cilTemp.planos_corte[i]].dire && res>0)){
					*t = INFINITY;
					inter.t = *t;
					return inter;
				}
			}
		}
	}


	long double d = (inter.Pint.x - cilTemp.rayo.ancla.x) * cilTemp.rayo.vector.dire.x
			+ (inter.Pint.y - cilTemp.rayo.ancla.y) * cilTemp.rayo.vector.dire.y
			+ (inter.Pint.z - cilTemp.rayo.ancla.z) * cilTemp.rayo.vector.dire.z;

	if (!(cilTemp.h1 <= d && d <= cilTemp.h2)){
		*t = MAX(temp1,temp2);
		inter.Pint.x = ray.ancla.x + *t * ray.vector.dire.x;
		inter.Pint.y = ray.ancla.y + *t * ray.vector.dire.y;
		inter.Pint.z = ray.ancla.z + *t * ray.vector.dire.z;
		d = (inter.Pint.x - cilTemp.rayo.ancla.x) * cilTemp.rayo.vector.dire.x
				+ (inter.Pint.y - cilTemp.rayo.ancla.y) * cilTemp.rayo.vector.dire.y
				+ (inter.Pint.z - cilTemp.rayo.ancla.z) * cilTemp.rayo.vector.dire.z;
		if (!(cilTemp.h1 <= d && d <= cilTemp.h2)){
			*t = INFINITY;
			inter.t = *t;
			return inter;
		}
		if (*t == INFINITY){
			inter.t = *t;
			return inter;
		}
	}
	//Mapas de Calado
	if (cilTemp.calado != -1 ){
		int ii,jj,pega;
		Vector N;
		Objeto Q;
		Q.obj = &cilTemp;
		N = NormalCilindro(&Q,inter.Pint);

		//	printf("d %LF\n",d);
		//	printf("cil %LF %LF %LF \n",inter.Pint.x,inter.Pint.y,inter.Pint.z);
		posicionTexturaCilindro(cilTemp,cilTemp.calado,inter.Pint,escena,&ii,&jj,N);

		pega = Calado(cilTemp.calado,ii,jj,escena);

		if (!pega && t2!=INFINITY && t2>EPSILON){
			*t = t2;
			inter.Pint.x = ray.ancla.x + *t * ray.vector.dire.x;
			inter.Pint.y = ray.ancla.y + *t * ray.vector.dire.y;
			inter.Pint.z = ray.ancla.z + *t * ray.vector.dire.z;
			N = NormalCilindro(&Q,inter.Pint);
			//	printf("cil %LF %LF %LF \n",inter.Pint.x,inter.Pint.y,inter.Pint.z);
			posicionTexturaCilindro(cilTemp,cilTemp.calado,inter.Pint,escena,&ii,&jj,N);

			pega = Calado(cilTemp.calado,ii,jj,escena);
			if (!pega){
				*t = INFINITY;
				inter.t = *t;
				return inter;
			}
		}
	}

	inter.d = d;
	inter.t = *t;

	return inter;
}

Interseccion InterCono(Rayo ray,long double *t,Cono conTemp,Escena *escena){

	long double a,b,c;
	long double discr;
	long double temp1,temp2;
	long double sqr;

	long double Xd,Yd,Zd;
	long double Xq,Yq,Zq;
	long double X0,Y0,Z0;
	long double Xe,Ye,Ze;
	long double A,B,C,D,E,F,G,H,I,J,K;
	long double t2;
	long double res;
	char nohay;
	int i;
	Punto Q = conTemp.rayo.vector.dire;
	Interseccion inter;

	Xe = ray.ancla.x;
	Ye = ray.ancla.y;
	Ze = ray.ancla.z;

	Xq = Q.x;
	Yq = Q.y;
	Zq = Q.z;

	Xd = ray.vector.dire.x;
	Yd = ray.vector.dire.y;
	Zd = ray.vector.dire.z;

	X0 = conTemp.rayo.ancla.x;
	Y0 = conTemp.rayo.ancla.y;
	Z0 = conTemp.rayo.ancla.z;

	A = conTemp.A;
	B = conTemp.B;
	C = conTemp.C;

	D = ((Xq * Xq * Xd) + (A * Yd) + (B * Zd) - Xd);
	E = ((Yq * Yq * Yd) + (A * Xd) + (C * Zd) - Yd);
	F = ((Zq * Zq * Zd) + (B * Xd) + (C * Yd) - Zd);
	G = (Xe - X0);
	H = (Ye - Y0);
	I = (Ze - Z0);
	J = conTemp.uv * conTemp.uv;
	K = ((Xq * Xd) + (Yq * Yd) + (Zq * Zd));

	a = ((D * D) + (E * E) + (F * F));
	a -= J * K * K;

	b = 2 * ((X0 * D) + (Y0 * E) + (Z0 * F) - (Xe * D) - (Ye * E) - (Ze * F)
			+ (G * ((Xq * Xq * D) + (E * A) + (F * B)))
			+ (H * ((D * A) + (Yq * Yq * E) + (F * C)))
			+ (I * ((D * B) + (E * C) + (Zq * Zq * F))));
	b -= 2 * J * ((Xq * K * G) + (Yq * K * H) + (Zq * K * I));

	c = (X0 * X0) + (Y0 * Y0) + (Z0 * Z0) + (Xe * Xe) + (Ye * Ye) + (Ze * Ze);
	c += (G * G * (pow(Xq,4) + (A * A) + (B * B)));
	c += (H * H * (pow(Yq,4) + (A * A) + (C * C)));
	c += (I * I * (pow(Zq,4) + (B * B) + (C * C)));
	c += 2 * (G * ((Xq * Xq)*(X0 - Xe) + A * (Y0 - Ye) + B * (Z0 - Ze)));
	c += 2 * (H * (A * (X0 - Xe) + (Yq * Yq) * (Y0 - Ye) + C * (Z0 - Ze)));
	c += 2 * (I * (B * (X0 - Xe) + C * (Y0 - Ye) + (Zq * Zq) * (Z0 - Ze)));
	c += (2 * G * H * (A * ((Xq * Xq) + (Yq * Yq)) + (B * C)));
	c += (2 * G * I * (B * ((Xq * Xq) + (Zq * Zq)) + (A * C)));
	c += (2 * H * I * ((A * B) + C * ((Yq * Yq) + (Zq * Zq))));
	c += -2 * ((X0 * Xe) + (Y0 * Ye) + (Z0 * Ze));
	c -= (2 * J * ((A * G * H) + I * ((B * G) + (C * H))));
	c -= (J * ((Xq * Xq * G * G) + (Yq * Yq * H * H) + (Zq * Zq * I * I)));

	discr = (b * b) - (4 * c * a);
	if (discr < 0){
		*t = INFINITY;
		inter.t = *t;
		return inter;
	}
	sqr = sqrtl(discr);
	temp1 = (-b + sqr)/(2.0 * a);
	temp2 = (-b - sqr)/(2.0 * a);
	inter.objeto.color = conTemp.color;
	if (temp1 < 0.0)
		temp1 = INFINITY;
	if (temp2 < 0.0)
		temp2 = INFINITY;
	*t = MIN(temp1,temp2);
	if (*t<=EPSILON){
		*t = MAX(temp1,temp2);
		t2 = MIN(temp1,temp2);
	}else{
		t2 = MAX(temp1,temp2);
	}
	inter.Pint.x = ray.ancla.x + *t * ray.vector.dire.x;
	inter.Pint.y = ray.ancla.y + *t * ray.vector.dire.y;
	inter.Pint.z = ray.ancla.z + *t * ray.vector.dire.z;

	nohay = 0;
	if (conTemp.cortes>0){
		for (i=0;i<conTemp.cortes;i++){
			res = escena->Planos[conTemp.planos_corte[i]].ABC.dire.x * inter.Pint.x;
			res += escena->Planos[conTemp.planos_corte[i]].ABC.dire.y * inter.Pint.y;
			res += escena->Planos[conTemp.planos_corte[i]].ABC.dire.z * inter.Pint.z;
			res += escena->Planos[conTemp.planos_corte[i]].D;
			if ((escena->Planos[conTemp.planos_corte[i]].dire && res<0)
					|| (!escena->Planos[conTemp.planos_corte[i]].dire && res>0)){
				nohay = 1;
			}
		}
		if (nohay){
			*t = t2;
			inter.Pint.x = ray.ancla.x + (*t) * ray.vector.dire.x;
			inter.Pint.y = ray.ancla.y + (*t) * ray.vector.dire.y;
			inter.Pint.z = ray.ancla.z + (*t) * ray.vector.dire.z;
			inter.t = *t;
			for (i=0;i<conTemp.cortes;i++){
				res = escena->Planos[conTemp.planos_corte[i]].ABC.dire.x * inter.Pint.x;
				res += escena->Planos[conTemp.planos_corte[i]].ABC.dire.y * inter.Pint.y;
				res += escena->Planos[conTemp.planos_corte[i]].ABC.dire.z * inter.Pint.z;
				res += escena->Planos[conTemp.planos_corte[i]].D;
				if ((escena->Planos[conTemp.planos_corte[i]].dire && res<0)
						|| (!escena->Planos[conTemp.planos_corte[i]].dire && res>0)){
					*t = INFINITY;
					inter.t = *t;
					return inter;
				}
			}
		}
	}

	long double d = (inter.Pint.x - conTemp.rayo.ancla.x) * conTemp.rayo.vector.dire.x
			+ (inter.Pint.y - conTemp.rayo.ancla.y) * conTemp.rayo.vector.dire.y
			+ (inter.Pint.z - conTemp.rayo.ancla.z) * conTemp.rayo.vector.dire.z;

	if (!(conTemp.h1 <= d && d <= conTemp.h2)){
		*t = MAX(temp1,temp2);
		inter.Pint.x = ray.ancla.x + *t * ray.vector.dire.x;
		inter.Pint.y = ray.ancla.y + *t * ray.vector.dire.y;
		inter.Pint.z = ray.ancla.z + *t * ray.vector.dire.z;
		d = (inter.Pint.x - conTemp.rayo.ancla.x) * conTemp.rayo.vector.dire.x
				+ (inter.Pint.y - conTemp.rayo.ancla.y) * conTemp.rayo.vector.dire.y
				+ (inter.Pint.z - conTemp.rayo.ancla.z) * conTemp.rayo.vector.dire.z;
		if (!(conTemp.h1 <= d && d <= conTemp.h2)){
			*t = INFINITY;
		}
	}

	inter.d = d;
	inter.t = *t;
	return inter;
}

Interseccion InterPoligono(Rayo ray,long double *t,Poligono poliTemp,Escena *escena){
	Interseccion inter;
	Vector ABC;
	long double D,denominador,m,b;
	int i,x,y;
	int xx,yy;
	long double res;

	xx=0;
	yy=0;
	ABC = poliTemp.Normal;
	D = poliTemp.D;
	denominador = ABC.dire.x * ray.vector.dire.x;
	denominador += ABC.dire.y * ray.vector.dire.y;
	denominador += ABC.dire.z * ray.vector.dire.z;
	if (denominador == 0){
		*t = INFINITY;
		inter.t = *t;
		return inter;
	}
	*t = ABC.dire.x * ray.ancla.x + ABC.dire.y * ray.ancla.y +
			ABC.dire.z * ray.ancla.z + D;
	*t *=-1.0;
	*t /= denominador;
	inter.objeto.color = poliTemp.color;
	//inter.
	inter.t = *t;

	inter.Pint.x = ray.ancla.x + *t * ray.vector.dire.x;
	inter.Pint.y = ray.ancla.y + *t * ray.vector.dire.y;
	inter.Pint.z = ray.ancla.z + *t * ray.vector.dire.z;
	if (poliTemp.aplastado == X){
		x = inter.Pint.y;
		y = inter.Pint.z;
	}else if (poliTemp.aplastado == Y){
		x = inter.Pint.x;
		y = inter.Pint.z;
	}else{
		x = inter.Pint.x;
		y = inter.Pint.y;
	}

	xx = 0;
	yy = 0;
	Punto p0,p1;
	int contaParedes=0;
	p0 = poliTemp.puntos[0];
	p0.x -=x; //trasladar
	p0.y -=y;
	for (i=1;i!=-2; i++){
		p1  = poliTemp.puntos[i];
		p1.x -=x; //trasladar
		p1.y -=y;
		if (p0.y == yy && p0.x > xx){
			contaParedes = 0;
			break;
		}else
			//Revisamos casos
			if (((p0.y > yy && p1.y < yy) || (p0.y < yy && p1.y > yy)) &&
					(p0.x > xx && p1.x > xx)){
				contaParedes++;
			}else if (!
					((p0.x < xx && p1.x < xx) ||
							(p0.y > yy && p1.y > yy) ||
							(p0.y < yy && p1.y < yy))
			){

				m = (p1.y - p0.y) / (p1.x - p0.x);
				b = (p0.y - m * p0.x);
				if ((-b / m)>xx)
					contaParedes++;
			}
		p0 = p1;
		if (i==poliTemp.numPuntos-1)
			i=-1;
		if (i==0){
			break;
		}
	}
	if (!(contaParedes % 2)){
		*t = INFINITY;
		inter.t = *t;
	}

	inter.t = *t;

	if (poliTemp.cortes>0){
		for (i=0;i<poliTemp.cortes;i++){
			res = escena->Planos[poliTemp.planos_corte[i]].ABC.dire.x * inter.Pint.x;
			res += escena->Planos[poliTemp.planos_corte[i]].ABC.dire.y * inter.Pint.y;
			res += escena->Planos[poliTemp.planos_corte[i]].ABC.dire.z * inter.Pint.z;
			res += escena->Planos[poliTemp.planos_corte[i]].D;
			if ((escena->Planos[poliTemp.planos_corte[i]].dire && res<0)
					|| (!escena->Planos[poliTemp.planos_corte[i]].dire && res>0)){
				*t = INFINITY;
				inter.t = *t;
				return inter;
			}
		}

	}

	if (poliTemp.disco==1 && NORMA(CREAR_VECTOR(poliTemp.centro,inter.Pint)) > poliTemp.radio){
		*t = INFINITY;
		inter.t = *t;
	}
	return inter;
}

Interseccion InterCuadratica(Rayo ray,long double *t,Cuadratica cuaTemp,Escena *escena){
	long double a,b,c;

	long double discr;
	long double temp1,temp2;
	long double sqr;
	long double t2;
	long double res;
	long double XD,YD,ZD;
	long double Xe,Ye,Ze;
	int i;
	char nohay;
	Interseccion inter;
	XD = ray.vector.dire.x;
	YD = ray.vector.dire.y;
	ZD = ray.vector.dire.z;
	Xe = ray.ancla.x;
	Ye = ray.ancla.y;
	Ze = ray.ancla.z;
	a = (cuaTemp.A * XD * XD) +  (cuaTemp.B * YD * YD) +  (cuaTemp.C * ZD * ZD)
				+ 2 * (cuaTemp.D*XD*YD + cuaTemp.E*YD*ZD + cuaTemp.F*XD*ZD);
	b = 2 * (
			cuaTemp.J*ZD
			+Xe*cuaTemp.F*ZD
			+Ye*cuaTemp.E*ZD
			+Ze*cuaTemp.C*ZD
			+cuaTemp.H*YD
			+Ze*cuaTemp.E*YD
			+Xe*cuaTemp.D*YD
			+Ye*cuaTemp.B*YD
			+cuaTemp.G*XD
			+Ze*cuaTemp.F*XD
			+Ye*cuaTemp.D*XD
			+Xe*cuaTemp.A*XD
	);
	c = cuaTemp.K
			+2*(Ze*cuaTemp.J
					+Ye*cuaTemp.H
					+Xe*cuaTemp.G
					+Xe*Ze*cuaTemp.F
					+Ye*Ze*cuaTemp.E
					+Xe*Ye*cuaTemp.D
			)
			+Ze*Ze*cuaTemp.C
			+Ye*Ze*cuaTemp.B
			+Xe*Xe*cuaTemp.A;
	discr = (b * b) - (4 * c * a);
	if (discr < 0){
		*t = INFINITY;
		inter.t = *t;
		return inter;
	}
	sqr = sqrtl(discr);
	temp1 = (-b + sqr)/(2.0 * a);
	temp2 = (-b - sqr)/(2.0 * a);
	inter.objeto.color = cuaTemp.color;
	if (temp1 < 0.0)
		temp1 = INFINITY;
	if (temp2 < 0.0)
		temp2 = INFINITY;

	*t = MIN(temp1,temp2);
	if (*t<EPSILON){
		*t = MAX(temp1,temp2);
		t2 = MIN(temp1,temp2);
	}else{
		t2 = MAX(temp1,temp2);
	}
	inter.t = *t;

	inter.Pint.x = ray.ancla.x + (*t) * ray.vector.dire.x;
	inter.Pint.y = ray.ancla.y + (*t) * ray.vector.dire.y;
	inter.Pint.z = ray.ancla.z + (*t) * ray.vector.dire.z;
	nohay = 0;
	if (cuaTemp.cortes>0){
		for (i=0;i<cuaTemp.cortes;i++){
			res = escena->Planos[cuaTemp.planos_corte[i]].ABC.dire.x * inter.Pint.x;
			res += escena->Planos[cuaTemp.planos_corte[i]].ABC.dire.y * inter.Pint.y;
			res += escena->Planos[cuaTemp.planos_corte[i]].ABC.dire.z * inter.Pint.z;
			res += escena->Planos[cuaTemp.planos_corte[i]].D;
			if ((escena->Planos[cuaTemp.planos_corte[i]].dire && res<0)
					|| (!escena->Planos[cuaTemp.planos_corte[i]].dire && res>0)){
				nohay = 1;

			}
		}
		if (nohay){
			*t = t2;
			inter.Pint.x = ray.ancla.x + (*t) * ray.vector.dire.x;
			inter.Pint.y = ray.ancla.y + (*t) * ray.vector.dire.y;
			inter.Pint.z = ray.ancla.z + (*t) * ray.vector.dire.z;
			inter.t = *t;
			for (i=0;i<cuaTemp.cortes;i++){
				res = escena->Planos[cuaTemp.planos_corte[i]].ABC.dire.x * inter.Pint.x;
				res += escena->Planos[cuaTemp.planos_corte[i]].ABC.dire.y * inter.Pint.y;
				res += escena->Planos[cuaTemp.planos_corte[i]].ABC.dire.z * inter.Pint.z;
				res += escena->Planos[cuaTemp.planos_corte[i]].D;
				if ((escena->Planos[cuaTemp.planos_corte[i]].dire && res<0)
						|| (!escena->Planos[cuaTemp.planos_corte[i]].dire && res>0)){
					*t = INFINITY;
					inter.t = *t;
					return inter;
				}
			}
		}
	}

	return inter;
}


void posicionTexturaPoligono(Poligono poli, int tex ,Punto pinter,Escena *escena, int *i, int *j){
	long double u,v,xx,yy;
	Vector vPinter;

	vPinter = CREAR_VECTOR(poli.puntos[0],pinter);
	u = PRODUCTO_PUNTO(vPinter,poli.U);
	v = PRODUCTO_PUNTO(vPinter,poli.V);
	xx=truncl(u/escena->Texturas[tex].mosaicoX);
	xx *=escena->Texturas[tex].mosaicoX;
	yy=truncl(v/escena->Texturas[tex].mosaicoY);
	yy *=escena->Texturas[tex].mosaicoY;

	u = u - xx;
	v = v - yy;
	u /= escena->Texturas[tex].mosaicoX;
	v /= escena->Texturas[tex].mosaicoY;
	*i = roundl( u * escena->Texturas[tex].resX);
	*j = roundl( v * escena->Texturas[tex].resY);
	if (*i<0)
		(*i)*=-1;
	if (*j<0)
		(*j)*=-1;
}

void posicionTexturaEsfera(Esfera esf, int tex ,Punto pinter,Escena *escena, int *i, int *j, Vector Normal){
	long double u,v;
	long double denominador,t;
	Punto pinter2;
	Vector H;
	v = 1- (acos(PRODUCTO_PUNTO(Normal,esf.Norte)))/(PI);

	denominador = esf.Norte.dire.x * -esf.Norte.dire.x;
	denominador += esf.Norte.dire.y * -esf.Norte.dire.y;
	denominador += esf.Norte.dire.z * -esf.Norte.dire.z;
	t = esf.Norte.dire.x  * pinter.x + esf.Norte.dire.y  * pinter.y +
			esf.Norte.dire.z * pinter.z + esf.Dnorte;
	t *=-1.0;

	t /= denominador;

	pinter2.x= pinter.x + t * -esf.Norte.dire.x;
	pinter2.y= pinter.y + t * -esf.Norte.dire.y;
	pinter2.z= pinter.z + t * -esf.Norte.dire.z;

	H = CREAR_VECTOR(esf.centro,pinter2);
	Normalizar(&H);
	u = acosl(PRODUCTO_PUNTO(H,esf.G));
	u /= (2*PI);

	if (esf.Correcto.dire.x*pinter.x
			+ esf.Correcto.dire.y*pinter.y
			+ esf.Correcto.dire.z*pinter.z
			+ esf.DCorrecto > 0.0){
		u = 1 - u;
	}

	v = MIN(v,1.0);
	v = MAX(v,0.0);
	u = MIN(u,1.0);
	u = MAX(u,0.0);

	*i = roundl( u * escena->Texturas[tex].resX);
	*j = roundl( v * escena->Texturas[tex].resY);
	if (*i<0)
		(*i)*=-1;
	if (*j<0)
		(*j)*=-1;
}

void posicionTexturaCilindro(Cilindro cil, int tex ,Punto pinter,Escena *escena, int *i, int *j, Vector Normal){
	long double u,v;
	Vector vec;
	vec = CREAR_VECTOR(cil.rayo.ancla,pinter);
	//Normalizar(&vec);
	v = PRODUCTO_PUNTO(vec,cil.rayo.vector) - cil.h1;
	//	v1 = v;
	v /= cil.h2 - cil.h1;


	u=PRODUCTO_PUNTO(Normal,cil.G);
	u = acosl(u);

	u /= (2 * PI);


	v = MIN(v,1.0);
	v = MAX(v,0.0);
	u = MIN(u,1.0);
	u = MAX(u,0.0);
	if (cil.Correcto.dire.x*pinter.x
			+ cil.Correcto.dire.y*pinter.y
			+ cil.Correcto.dire.z*pinter.z
			+ cil.D > 0.0){
		u = 1 - u;
	}

	*i = roundl( u * escena->Texturas[tex].resX);
	*j = roundl( v * escena->Texturas[tex].resY);
	if (*i<0)
		(*i)*=-1;
	if (*j<0)
		(*j)*=-1;

	if (*i> escena->Texturas[tex].resX || *j> escena->Texturas[tex].resY){
		printf("\n\ncilindro %d: %d %d %d %d\n",tex,escena->Texturas[tex].resX,escena->Texturas[tex].resY, *i, *j);
	}
}
void rotarPunto(Punto *aRotar, Vector u, Vector v, Vector n){
	Vector original;
	original.dire = *aRotar;
	Vector _n;
	_n.dire.x = -n.dire.x;
	_n.dire.y = -n.dire.y;
	_n.dire.z = -n.dire.z;
	aRotar->x = PRODUCTO_PUNTO(original,u);
	aRotar->y = PRODUCTO_PUNTO(original,v);
	aRotar->z = PRODUCTO_PUNTO(original,_n);
}
void rotarVector(Vector *aRotar, Vector u, Vector v, Vector n){
	rotarPunto(&(aRotar->dire),u,v,n);
	Normalizar(aRotar);
}
void trasladarPunto(Punto *punto, Punto vrp){
	punto->x -= vrp.x;
	punto->y -= vrp.y;
	punto->z -= vrp.z;
}
void trasladarEsfera(Esfera *esf,Punto vrp){
	trasladarPunto(&(esf->centro),vrp);
}
void rotarEsfera(Esfera *esf, Vector u, Vector v, Vector n){
	rotarPunto(&(esf->centro),u,v,n);
	rotarVector(&(esf->G),u,v,n);
	rotarVector(&(esf->Norte),u,v,n);
	rotarVector(&(esf->Correcto),u,v,n);
	rotarVector(&(esf->U),u,v,n);
	rotarVector(&(esf->V),u,v,n);
}

void trasladarCilindro(Cilindro *cil,Punto vrp){
	trasladarPunto(&(cil->rayo.ancla),vrp);
}
void rotarCilindro(Cilindro *cil, Vector u, Vector v, Vector n){
	rotarPunto(&(cil->rayo.ancla),u,v,n);
	rotarVector(&(cil->rayo.vector),u,v,n);
	rotarVector(&(cil->G),u,v,n);
	rotarVector(&(cil->Correcto),u,v,n);
	rotarVector(&(cil->U),u,v,n);
	rotarVector(&(cil->V),u,v,n);
}

void trasladarPoligono(Poligono *poli,Punto vrp){
	int i=0;
	for (i=0; i<poli->numPuntos; i++){

		trasladarPunto(&(poli->puntos[i]),vrp);
	}
	//Para el disco, si existiera
	trasladarPunto(&(poli->centro),vrp);
}
void rotarPoligono(Poligono *poli, Vector u, Vector v, Vector n){
	int i=0;
	for (i=0; i<poli->numPuntos; i++){
		rotarPunto(&(poli->puntos[i]),u,v,n);
	}
	//Para el disco, si existiera
	rotarPunto(&(poli->centro),u,v,n);
	rotarVector(&(poli->Normal),u,v,n);
	rotarVector(&(poli->U),u,v,n);
	rotarVector(&(poli->V),u,v,n);
}

void trasladarCono(Cono *con,Punto vrp){
	trasladarPunto(&(con->rayo.ancla),vrp);
}
void rotarCono(Cono *con, Vector u, Vector v, Vector n){
	rotarPunto(&(con->rayo.ancla),u,v,n);
	rotarVector(&(con->rayo.vector),u,v,n);
}




